#include "Sampler.h"

#include <Runtime/Graphics/Device/GraphicsDevice.h>

Sampler::Sampler(std::shared_ptr<GraphicsDevice> device, const SamplerDesc& desc) {
	mOwnerDevice = device;

	mFilter = desc.Filter;
	mAddressU = desc.AddressU;
	mAddressV = desc.AddressV;
	mAddressW = desc.AddressW;
	mMipLODBias = desc.MipLODBias;
	mMaxAnisotropy = desc.MaxAnisotropy;
	mSamplerComparison = desc.SamplerComparison;
	for (int i = 0; i < 4; i++) { mBorderColor[i] = desc.BorderColor[i]; }
	mMinLOD = desc.MinLOD;
	mMaxLOD = desc.MaxLOD;

	D3D11_SAMPLER_DESC samplerDesc = {};
	samplerDesc.Filter = SamplerUtils::GetSamplerFilter(mFilter);
	samplerDesc.AddressU = SamplerUtils::GetSamplerAddressMode(mAddressU);
	samplerDesc.AddressV = SamplerUtils::GetSamplerAddressMode(mAddressV);
	samplerDesc.AddressW = SamplerUtils::GetSamplerAddressMode(mAddressW);
	samplerDesc.MipLODBias = mMipLODBias;
	samplerDesc.MaxAnisotropy = mMaxAnisotropy;
	samplerDesc.ComparisonFunc = SamplerUtils::GetSamplerComparisonFunc(mSamplerComparison);
	for (int i = 0; i < 4; i++) { samplerDesc.BorderColor[i] = mBorderColor[i]; }
	samplerDesc.MinLOD = mMinLOD;
	samplerDesc.MaxLOD = mMaxLOD;

	DEV_ASSERT(SUCCEEDED(device->GetD3D11Device()->CreateSamplerState(&samplerDesc,
		mSamplerState.GetAddressOf())), "Sampler", "Failed to create sampler state.");
}


D3D11_FILTER SamplerUtils::GetSamplerFilter(SampleFilter filter) {
	switch (filter) {
	case SampleFilter::MIN_MAG_MIP_POINT:
		return D3D11_FILTER_MIN_MAG_MIP_POINT;
	case SampleFilter::MIN_MAG_POINT_MIP_LINEAR:
		return D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR;
	case SampleFilter::MIN_POINT_MAG_LINEAR_MIP_POINT:
		return D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT;
	case SampleFilter::MIN_POINT_MAG_MIP_LINEAR:
		return D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR;
	case SampleFilter::MIN_LINEAR_MAG_MIP_POINT:
		return D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT;
	case SampleFilter::MIN_LINEAR_MAG_POINT_MIP_LINEAR:
		return D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
	case SampleFilter::MIN_MAG_LINEAR_MIP_POINT:
		return D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT;
	case SampleFilter::MIN_MAG_MIP_LINEAR:
		return D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	case SampleFilter::ANISOTROPIC:
		return D3D11_FILTER_ANISOTROPIC;
	case SampleFilter::COMPARISON_MIN_MAG_MIP_POINT:
		return D3D11_FILTER_COMPARISON_MIN_MAG_MIP_POINT;
	case SampleFilter::COMPARISON_MIN_MAG_POINT_MIP_LINEAR:
		return D3D11_FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR;
	case SampleFilter::COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT:
		return D3D11_FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT;
	case SampleFilter::COMPARISON_MIN_POINT_MAG_MIP_LINEAR:
		return D3D11_FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR;
	case SampleFilter::COMPARISON_MIN_LINEAR_MAG_MIP_POINT:
		return D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT;
	case SampleFilter::COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
		return D3D11_FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
	case SampleFilter::COMPARISON_MIN_MAG_LINEAR_MIP_POINT:
		return D3D11_FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT;
	case SampleFilter::COMPARISON_MIN_MAG_MIP_LINEAR:
		return D3D11_FILTER_COMPARISON_MIN_MAG_MIP_LINEAR;
	case SampleFilter::COMPARISON_ANISOTROPIC:
		return D3D11_FILTER_COMPARISON_ANISOTROPIC;
	case SampleFilter::MINIMUM_MIN_MAG_MIP_POINT:
		return D3D11_FILTER_MINIMUM_MIN_MAG_MIP_POINT;
	case SampleFilter::MINIMUM_MIN_MAG_POINT_MIP_LINEAR:
		return D3D11_FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR;
	case SampleFilter::MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT:
		return D3D11_FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT;
	case SampleFilter::MINIMUM_MIN_POINT_MAG_MIP_LINEAR:
		return D3D11_FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR;
	case SampleFilter::MINIMUM_MIN_LINEAR_MAG_MIP_POINT:
		return D3D11_FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT;
	case SampleFilter::MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
		return D3D11_FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
	case SampleFilter::MINIMUM_MIN_MAG_LINEAR_MIP_POINT:
		return D3D11_FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT;
	case SampleFilter::MINIMUM_MIN_MAG_MIP_LINEAR:
		return D3D11_FILTER_MINIMUM_MIN_MAG_MIP_LINEAR;
	case SampleFilter::MINIMUM_ANISOTROPIC:
		return D3D11_FILTER_MAXIMUM_ANISOTROPIC;
	case SampleFilter::MAXIMUM_MIN_MAG_MIP_POINT:
		return D3D11_FILTER_MAXIMUM_MIN_MAG_MIP_POINT;
	case SampleFilter::MAXIMUM_MIN_MAG_POINT_MIP_LINEAR:
		return D3D11_FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR;
	case SampleFilter::MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT:
		return D3D11_FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT;
	case SampleFilter::MAXIMUM_MIN_POINT_MAG_MIP_LINEAR:
		return D3D11_FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR;
	case SampleFilter::MAXIMUM_MIN_LINEAR_MAG_MIP_POINT:
		return D3D11_FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT;
	case SampleFilter::MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR:
		return D3D11_FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR;
	case SampleFilter::MAXIMUM_MIN_MAG_LINEAR_MIP_POINT:
		return D3D11_FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT;
	case SampleFilter::MAXIMUM_MIN_MAG_MIP_LINEAR:
		return D3D11_FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR;
	case SampleFilter::MAXIMUM_ANISOTROPIC:
		return D3D11_FILTER_MAXIMUM_ANISOTROPIC;
	}
	return D3D11_FILTER_MIN_MAG_MIP_POINT;
}

D3D11_TEXTURE_ADDRESS_MODE SamplerUtils::GetSamplerAddressMode(AddressMode addressMode) {
	switch (addressMode) {
	case AddressMode::WRAP:
		return D3D11_TEXTURE_ADDRESS_WRAP;
	case AddressMode::MIRROR:
		return D3D11_TEXTURE_ADDRESS_MIRROR;
	case AddressMode::CLAMP:
		return D3D11_TEXTURE_ADDRESS_CLAMP;
	case AddressMode::BORDER:
		return D3D11_TEXTURE_ADDRESS_BORDER;
	case AddressMode::MIRROR_ONCE:
		return D3D11_TEXTURE_ADDRESS_MIRROR_ONCE;
	}
	return D3D11_TEXTURE_ADDRESS_WRAP;
}

D3D11_COMPARISON_FUNC SamplerUtils::GetSamplerComparisonFunc(SamplerComparison comparison) {
	switch (comparison) {
	case SamplerComparison::NEVER:
		return D3D11_COMPARISON_NEVER;
	case SamplerComparison::LESS:
		return D3D11_COMPARISON_LESS;
	case SamplerComparison::EQUAL:
		return D3D11_COMPARISON_EQUAL;
	case SamplerComparison::LESS_EQUAL:
		return D3D11_COMPARISON_LESS_EQUAL;
	case SamplerComparison::GREATER:
		return D3D11_COMPARISON_GREATER;
	case SamplerComparison::NOT_EQUAL:
		return D3D11_COMPARISON_NOT_EQUAL;
	case SamplerComparison::GREATER_EQUAL:
		return D3D11_COMPARISON_GREATER_EQUAL;
	case SamplerComparison::ALWAYS:
		return D3D11_COMPARISON_ALWAYS;
	}
	return D3D11_COMPARISON_NEVER;
}
